package com.whfc.mach.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.whfc.common.constant.QueueConst;
import com.whfc.common.enums.*;
import com.whfc.common.exception.BizException;
import com.whfc.common.file.FileHandler;
import com.whfc.common.file.FilePathConfig;
import com.whfc.common.file.properties.FileExpirationRules;
import com.whfc.common.result.ListData;
import com.whfc.common.result.PageData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.*;
import com.whfc.entity.dto.Apply.req.EquipmentIdReq;
import com.whfc.fuum.entity.WxUser;
import com.whfc.fuum.service.SysDeptService;
import com.whfc.hdc.dto.AppDeviceCmdDTO;
import com.whfc.hdc.service.AppDeviceService;
import com.whfc.mach.MachOilAddDel;
import com.whfc.mach.dao.*;
import com.whfc.mach.dto.*;
import com.whfc.mach.dto.obd.ObdMaintainDTO;
import com.whfc.mach.entity.*;
import com.whfc.mach.enums.MachState;
import com.whfc.mach.enums.MaintainState;
import com.whfc.mach.manager.MachDataManager;
import com.whfc.mach.manager.MachMgr;
import com.whfc.mach.manager.ObdDataMgr;
import com.whfc.mach.param.*;
import com.whfc.mach.service.AppMachService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.jboss.logging.Param;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.*;

/**
 * @author qzexing
 * @version 1.0
 * @date 2020-11-06 15:53
 */
@DubboService(interfaceClass = AppMachService.class, version = "1.0.0", timeout = 10000)
public class AppMachServiceImpl implements AppMachService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AppMachMapper appMachMapper;

    @Autowired
    private AppMachDataMapper appMachDataMapper;

    @Autowired
    private AppMachDayMapper appMachDayMapper;

    @Autowired
    private AppMachDeviceMapper appMachDeviceMapper;

    @Autowired
    private AppMachOperEmpMapper appMachOperEmpMapper;

    @Autowired
    private AppMachOilRecordMapper appMachOilRecordMapper;

    @Autowired
    private AppMachImgMapper machImgMapper;

    @Autowired
    private MachMgr machMgr;

    @Autowired
    private ObdDataMgr obdDataMgr;

    @Autowired
    private MachDataManager machDataMgr;

    @DubboReference(interfaceClass = SysDeptService.class, version = "1.0.0")
    private SysDeptService sysDeptService;

    @DubboReference(interfaceClass = AppDeviceService.class, version = "1.0.0")
    private AppDeviceService commonDeviceService;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private FileHandler fileHandler;

    @Autowired
    private FilePathConfig filePathConfig;

    /**
     * 临时文件目录
     */
    private static final String PATH = "mach/tmp";

    /**
     * 一天的秒数
     */
    private static final double ONE_DAY_SECORDS = 24 * 3600;

    /**
     * 硬件开关机指令
     */
    private static final int CMD = 0x8B;

    /**
     *
     */
    private static final List<Integer> deviceTypes = Arrays.asList(DeviceType.mach.getValue(), DeviceType.obd.getValue(), DeviceType.cloudm.getValue());


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer add(MachAddParam param) {
        logger.info("添加设备服务,param:{}", param.toString());
        String machCode = param.getMachCode();
        Integer deptId = param.getDeptId();
        AppMach appMach = appMachMapper.selectByDeptIdAndMachCode(deptId, machCode);
        if (appMach != null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该设备编号已存在");
        }

        // 新增设备信息
        AppMach mach = new AppMach();
        BeanUtils.copyProperties(param, mach);
        mach.setHoldDeptId(deptId);
        mach.setState(MachState.IN.getValue());
        appMachMapper.insertSelective(mach);
        Integer machId = mach.getId();

        // 插入照片
        List<String> imgList = param.getImgList();
        if (imgList != null && imgList.size() > 0) {
            machImgMapper.batchInsert(machId, imgList);
        }

        // 插入操作手
        List<MachOperEmpParam> operEmpList = param.getOperEmpList();
        if (operEmpList != null && operEmpList.size() > 0) {
            appMachOperEmpMapper.batchInsert(machId, operEmpList);
        }

        this.initMachData(machId);
        return machId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addWxMach(WxUser wxUser, WxMachAddParam param) {
        logger.info("添加并绑定设备服务,user:{},param:{}", wxUser.getPhone(), param.toString());
        Integer deviceType = param.getDeviceType();
        if (!deviceTypes.contains(deviceType)) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该硬件类型错误");
        }
        // 校验设备有无绑定
        Integer deviceId = param.getDeviceId();
        String sn = param.getSn();
        AppMachDevice machDevice = appMachDeviceMapper.selectByDeviceId(deviceId);
        if (machDevice != null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "硬件已经被其他人绑定");
        }

        // 添加设备
        MachAddParam request = new MachAddParam();
        BeanUtils.copyProperties(param, request);
        Integer machId = this.add(request);

        // 绑定设备
        machMgr.bind(machId, deviceId, wxUser.getId(), wxUser.getNickName());

        // 更新app_mach中的綁定信息
        appMachMapper.updateBindFlagByMachId(machId, BindFlag.BIND.getValue(), sn, deviceId, deviceType);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(MachEditParam param) {
        logger.info("编辑设备服务,param:{}", param.toString());
        Integer machId = param.getMachId();
        String machCode = param.getMachCode();
        Integer deptId = param.getDeptId();
        AppMach appMach = appMachMapper.selectByDeptIdAndMachCode(deptId, machCode);
        if (appMach != null && !appMach.getId().equals(machId)) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该设备编号已存在");
        }

        // 更新设备信息
        AppMach mach = new AppMach();
        BeanUtils.copyProperties(param, mach);
        mach.setId(machId);
        mach.setHoldDeptId(deptId);
        appMachMapper.updateByPrimaryKeySelective(mach);

        appMachMapper.updateQrByMachId(machId, null);

        // 修改设备照片
        List<String> imgList = param.getImgList();
        machImgMapper.deleteLogicByMachId(machId);
        if (imgList != null && imgList.size() > 0) {
            machImgMapper.batchInsert(machId, imgList);
        }

        // 修改操作手信息
        List<MachOperEmpParam> operEmpList = param.getOperEmpList();
        appMachOperEmpMapper.deleteLogicByMachId(machId);
        if (operEmpList != null && operEmpList.size() > 0) {
            appMachOperEmpMapper.batchInsert(machId, operEmpList);
        }
    }

    @Override
    public void editMachTank(MachTankEditParam param) {
        logger.info("编辑设备油箱服务,param:{}", param.toString());
        Integer machId = param.getMachId();
        Double oilTankHeight = param.getOilTankHeight();
        Double oilTankVolume = param.getOilTankVolume();
        appMachMapper.updateTank(machId, oilTankHeight, oilTankVolume);
    }

    @Override
    public String export(List<Integer> deptIds) {
        logger.info("导出设备信息服务,deptIds:{}", deptIds);
        String upload = "";
        // 获取数据
        List<AppMachDTO> list = appMachMapper.selectMachDTOByDeptIds(deptIds);
        try {
            // 获取模板
            ClassPathResource resource = new ClassPathResource("templates/machInfoTemplate.xls");
            InputStream templateFileInputStream = resource.getInputStream();
            File tempFile = FileUtil.copyTemplateFile(templateFileInputStream);

            // 写数据
            FileInputStream fileInputStream = new FileInputStream(tempFile);
            HSSFWorkbook workbook = new HSSFWorkbook(fileInputStream);
            HSSFSheet sheet = workbook.getSheetAt(0);

            // 填充数据
            int rowIdx = 1;
            for (AppMachDTO appMachDTO : list) {
                this.fillExcelData(sheet, appMachDTO, rowIdx);
                rowIdx++;
            }

            // 保存excel
            FileOutputStream fos = new FileOutputStream(tempFile);
            workbook.write(fos);
            fos.flush();
            fos.close();

            // 上传oss
            FileInputStream inputStream = new FileInputStream(tempFile);
            String path = filePathConfig.getFilePath(PATH, RandomUtil.getRandomFileName(), "xls");
            upload = fileHandler.upload(path, inputStream, FileExpirationRules.DAYS_1);
        } catch (Exception e) {
            logger.warn("导出设备信息失败.", e);
            throw new BizException(ResultEnum.FAILURE.getCode(), "导出设备信息失败");
        }
        return upload;
    }

    @Override
    public String exportObd(List<Integer> deptIds) throws BizException {
        logger.info("导出电力设备信息服务,deptIds:{}", deptIds);
        String upload = "";
        // 获取数据
        List<AppMachDTO> list = appMachMapper.selectMachDTOByDeptIds(deptIds);
        Map<Integer, String> deptNameMap = sysDeptService.getDeptNameMap(deptIds);
        Map<Integer, ObdMaintainDTO> machMaintainMap = obdDataMgr.getMachMaintainInfo(deptIds);
        for (AppMachDTO appMachDTO : list) {
            appMachDTO.setDeptName(deptNameMap.get(appMachDTO.getDeptId()));
            // 查找设备是否需要保养
            ObdMaintainDTO obdMaintainDTO = machMaintainMap.get(appMachDTO.getMachId());
            if (obdMaintainDTO == null) {
                appMachDTO.setMaintainState(MaintainState.MAINTAIN.getValue());
            } else {
                appMachDTO.setMaintainState(obdMaintainDTO.getState());
                appMachDTO.setMaintainTime(obdMaintainDTO.getMaintainTime());
            }
        }
        try {
            // 获取模板
            ClassPathResource resource = new ClassPathResource("templates/obdInfoTemplate.xls");
            InputStream templateFileInputStream = resource.getInputStream();
            File tempFile = FileUtil.copyTemplateFile(templateFileInputStream);

            // 写数据
            FileInputStream fileInputStream = new FileInputStream(tempFile);
            HSSFWorkbook workbook = new HSSFWorkbook(fileInputStream);
            HSSFSheet sheet = workbook.getSheetAt(0);

            // 填充数据
            int rowIdx = 1;
            for (AppMachDTO appMachDTO : list) {
                this.fillObdData(sheet, appMachDTO, rowIdx);
                rowIdx++;
            }

            // 保存excel
            FileOutputStream fos = new FileOutputStream(tempFile);
            workbook.write(fos);
            fos.flush();
            fos.close();

            // 上传oss
            FileInputStream inputStream = new FileInputStream(tempFile);
            String path = filePathConfig.getFilePath(PATH, RandomUtil.getRandomFileName(), "xls");
            upload = fileHandler.upload(path, inputStream, FileExpirationRules.DAYS_1);

        } catch (Exception e) {
            logger.warn("导出obd设备信息失败.", e);
            throw new BizException(ResultEnum.FAILURE.getCode(), "导出obd设备信息失败");
        }
        return upload;
    }


    @Override
    public void unbindMachDevice(Integer userId, String userName, Integer machId) throws BizException {
        machMgr.unbind(machId, userId, userName);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bindMachDevice(DeviceMachBindParam param) {
        String sn = param.getSn();
        Integer machId = param.getMachId();
        Integer deviceId = param.getDeviceId();
        Integer deviceType = param.getDeviceType();
        if (!deviceTypes.contains(deviceType)) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该硬件类型错误");
        }
        // 查找设备
        AppMach mach = appMachMapper.selectByPrimaryKey(machId);
        if (mach == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "未找到该设备");
        }
        if (BindFlag.BIND.getValue().equals(mach.getBindFlag())) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该设备已经绑定");
        }

        // 查找该硬件的绑定状态
        AppMachDevice machDevice = appMachDeviceMapper.selectByDeviceId(deviceId);
        if (machDevice != null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "硬件已经被其他人绑定");
        }

        // 绑定
        machMgr.bind(machId, deviceId, param.getUserId(), param.getNickName());

        //更新app_mach中的綁定信息
        appMachMapper.updateBindFlagByMachId(machId, BindFlag.BIND.getValue(), sn, deviceId, deviceType);
    }

    /**
     * 初始化设备数据
     *
     * @param machId 设备ID
     */
    private void initMachData(Integer machId) {
        AppMachData record = new AppMachData();
        record.setMachId(machId);
        record.setTime(new Date());
        record.setNetState(NetState.OFFLINE.getValue());
        record.setDelFlag(DelFlag.UNDELETE.getValue());
        record.setWorkState(WorkState.STOP.getValue());
        record.setTotalLength1(0L);
        record.setTotalLength2(0L);
        record.setTotalWorkHours(0D);
        record.setTotalOilWear(0D);
        appMachDataMapper.insertOrUpdate(record);
    }

    /**
     * 填充excel数据
     *
     * @param sheet
     * @param appMachDTO
     */
    private void fillExcelData(HSSFSheet sheet, AppMachDTO appMachDTO, Integer rowIdx) {
        MachInfoExcelDTO machInfoExcelDTO = this.changeData(appMachDTO);

        HSSFRow row = sheet.createRow(rowIdx);
        HSSFCell cell0 = row.createCell(0);
        String machCode = machInfoExcelDTO.getMachCode();
        cell0.setCellValue(machCode == null ? "-" : machCode);

        HSSFCell cell1 = row.createCell(1);
        String machTypeName = machInfoExcelDTO.getMachTypeName();
        cell1.setCellValue(machTypeName == null ? "-" : machTypeName);

        HSSFCell cell2 = row.createCell(2);
        String machModelName = machInfoExcelDTO.getMachModelName();
        cell2.setCellValue(machModelName == null ? "-" : machModelName);

        HSSFCell cell3 = row.createCell(3);
        String corpName = machInfoExcelDTO.getCorpName();
        cell3.setCellValue(corpName == null ? "-" : corpName);

        HSSFCell cell4 = row.createCell(4);
        String deliveryTimeStr = machInfoExcelDTO.getDeliveryTimeStr();
        cell4.setCellValue(deliveryTimeStr == null ? "-" : deliveryTimeStr);

        HSSFCell cell5 = row.createCell(5);
        String enterTimeStr = machInfoExcelDTO.getEnterTimeStr();
        cell5.setCellValue(enterTimeStr == null ? "-" : enterTimeStr);

        HSSFCell cell6 = row.createCell(6);
        String outerTimeStr = machInfoExcelDTO.getOuterTimeStr();
        cell6.setCellValue(outerTimeStr == null ? "-" : outerTimeStr);

        HSSFCell cell7 = row.createCell(7);
        Double totalWorkHours = machInfoExcelDTO.getTotalWorkHours();
        cell7.setCellValue(totalWorkHours == null ? 0D : totalWorkHours);

        HSSFCell cell8 = row.createCell(8);
        String names = machInfoExcelDTO.getNames();
        cell8.setCellValue(names == null ? "-" : names);

        HSSFCell cell9 = row.createCell(9);
        String phones = machInfoExcelDTO.getPhones();
        cell9.setCellValue(phones == null ? "-" : phones);

        HSSFCell cell10 = row.createCell(10);
        String certs = machInfoExcelDTO.getCerts();
        cell10.setCellValue(certs == null ? "-" : certs);

        HSSFCell cell11 = row.createCell(11);
        String sn = machInfoExcelDTO.getSn();
        cell11.setCellValue(sn == null ? "-" : sn);

        HSSFCell cell12 = row.createCell(12);
        Double oilTankVolume = machInfoExcelDTO.getOilTankVolume();
        cell12.setCellValue(oilTankVolume == null ? 0D : oilTankVolume);

        HSSFCell cell13 = row.createCell(13);
        Double oilTankHeight = machInfoExcelDTO.getOilTankHeight();
        cell13.setCellValue(oilTankHeight == null ? 0D : oilTankHeight);
    }


    @Override
    public PageData<OpenApiMachDTO> openApiMachList(Integer deptId, Integer pageNum, Integer pageSize) {
        logger.info("openApi,开始查询设备列表（分页），deptId：{}，pageNum：{}，pageSize：{}", deptId, pageNum, pageSize);
        PageHelper.startPage(pageNum, pageSize);
        List<OpenApiMachDTO> list = appMachMapper.selectOpenApiMachDTOList(deptId);
        PageInfo<OpenApiMachDTO> pageInfo = PageInfo.of(list);
        return PageUtil.pageData(pageInfo);
    }

    @Override
    public List<OpenApiMachDTO> openApiMachList(Integer deptId) {
        logger.info("openApi,开始查询设备列表（不分页），deptId：{}", deptId);
        return appMachMapper.selectOpenApiMachDTOList(deptId);
    }

    @Override
    public OpenApiMachDTO openApiMachDetail(Integer machId) {
        logger.info("openApi，开始查询设备详情,machId:{}", machId);
        return appMachMapper.selectOpenApiMachDTO(machId);
    }

    @Override
    public AppMachWorkHourDayDTO openApiMachWorkHour(Integer machId, Date date) {
        //每日统计数据
        AppMachWorkHourDayDTO workHour = new AppMachWorkHourDayDTO();
        workHour.setWorkTimes(0D);
        workHour.setIdleTimes(0D);

        AppMachDayDTO dayDTO = appMachDayMapper.selectByMachIdAndDate(machId, date);
        if (dayDTO != null) {
            Date now = new Date();
            Date today = DateUtil.getDate(now);
            double totalTimes = today.getTime() == date.getTime() ? (now.getTime() - today.getTime()) / 1000 : ONE_DAY_SECORDS;

            //每日分段数据
            List<AppMachDaySegDTO> machDaySegDTOS = machDataMgr.getMachDaySegList(machId, date);
            if (machDaySegDTOS.size() > 0) {
                // 计算停机时长
                double stopTimes = totalTimes - workHour.getWorkTimes() - workHour.getIdleTimes();
                workHour.setTimesArr(machDaySegDTOS);
                workHour.setStopTimes(stopTimes);
                return workHour;
            }
            workHour.setStopTimes(totalTimes);
            workHour.setTimesArr(Collections.emptyList());
        }

        return workHour;
    }

    @Override
    public OpenApiOilWearDTO openApiMachOilWear(Integer machId, Date date) {
        AppMach appMach = appMachMapper.selectByPrimaryKey(machId);
        if (appMach == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该设备不存在");
        }
        AppMachDayDTO dayDTO = appMachDayMapper.selectByMachIdAndDate(machId, date);
        if (dayDTO == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "当天没有数据");
        }
        OpenApiOilWearDTO data = new OpenApiOilWearDTO();
        data.setDate(date);
        data.setMachId(machId);
        data.setOilTankHeight(appMach.getOilTankHeight());
        data.setOilTankVolume(appMach.getOilTankVolume());
        data.setOilAdd(dayDTO.getOilAdd());
        data.setOilWear(dayDTO.getOilWear());
        return data;
    }

    @Override
    public void enter(MachEnterParam param) {
        appMachMapper.updateEnterStateByMachId(param.getMachId(), param.getTime());
    }

    @Override
    public void outer(MachEnterParam param) {
        appMachMapper.updateOuterStateByMachId(param.getMachId(), param.getTime());
    }

    @Override
    public void del(Integer machId) {
        logger.info("删除设备服务,machId:{}", machId);
        AppMachDevice machDevice = appMachDeviceMapper.selectByMachId(machId);
        if (machDevice != null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该设备处于绑定状态，不能删除！");
        }
        appMachMapper.logicDeleteById(machId);
    }

    @Override
    public ListData<AppMachTypeDTO> machTypeList(List<Integer> deptIds) {
        logger.info("获取设备类型列表服务,deptIds:{}", deptIds.toString());
        List<AppMachTypeDTO> list = appMachMapper.selectMachTypeList(deptIds);
        return new ListData<>(list);
    }

    @Override
    public Boolean bindCheck(Integer deviceId) {
        logger.info("验证硬件是否被绑定服务,deviceId:{}", deviceId);
        AppMachDevice appMachDevice = appMachDeviceMapper.selectByDeviceId(deviceId);
        return appMachDevice != null;
    }

    @Deprecated
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setOilAdd(MachSetOilAddParam param) {
        logger.info("标定设备加油量服务,param:{}", param.toString());
    }

    @Deprecated
    @Override
    public ListData<MachOilAdd> getOilAdd(Integer machId, Date date) {
        logger.info("获取标定设备加油量详情服务,machId:{},date:{}", machId, date);
        return new ListData<>(Collections.emptyList());
    }

    @Override
    public PageData<AppMachOilRecordDTO> getOilRecordList(Integer deptId, Date startDate, Date endDate, String keyword, Integer pageNum, Integer pageSize) throws BizException {
        logger.info("获取标定项目加油量,deptId:{},startDate:{},endDate:{},keyword:{},pageNum:{},pageSize:{}", deptId, startDate, endDate, keyword, pageNum, pageSize);
        Date startTime = DateUtil.getDateBegin(startDate);
        Date endTime = DateUtil.getDateEnd(endDate);
        PageHelper.startPage(pageNum, pageSize);
        List<AppMachOilRecordDTO> list = appMachOilRecordMapper.selectOilAddByDeptIdAndTimeRange(deptId, startTime, endTime, keyword);
        PageHelper.clearPage();
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public PageData<AppMachOilRecordDTO> getOilRecordList(Integer machId, Date startDate, Date endDate, Integer pageNum, Integer pageSize) throws BizException {
        logger.info("获取设备加油量,machId:{},startDate:{},endDate:{}", machId, startDate, endDate);
        Date startTime = DateUtil.getDateBegin(startDate);
        Date endTime = DateUtil.getDateEnd(endDate);
        PageHelper.startPage(pageNum, pageSize);
        List<AppMachOilRecordDTO> list = appMachOilRecordMapper.selectOilAddByMachIdAndTimeRange(machId, startTime, endTime);
        PageHelper.clearPage();
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public void addOilManual(MachOilAddManual param) throws BizException {
        Integer machId = param.getMachId();
        Date time = param.getTime();
        AppMachOilRecord record = appMachOilRecordMapper.selectOilAddByMachIdAndTime(machId, time);
        if (record == null) {
            record = new AppMachOilRecord();
            record.setMachId(param.getMachId());
            record.setTime(param.getTime());
        }
        record.setOilAddManual(param.getOilAddManual());
        record.setOilAddCost(param.getOilAddCost());
        record.setOilAddType(param.getOilAddType());
        if (ObjectUtils.isEmpty(record.getId())) {
            appMachOilRecordMapper.insertSelective(record);
        } else {
            appMachOilRecordMapper.updateByPrimaryKeySelective(record);
        }
    }

    @Override
    public void addOilAdjust(MachOilAddAdjust param) throws BizException {
        Integer machId = param.getMachId();
        Date time = param.getTime();
        AppMachOilRecord record = appMachOilRecordMapper.selectOilAddByMachIdAndTime(machId, time);
        if (record != null && record.getOilAddHardware() != null && record.getOilAddHardware() > 0) {
            record.setOilAddAdjust(param.getOilAddAdjust());
            record.setOilAdd(param.getOilAddAdjust());
            record.setOilAddCost(param.getOilAddCost());
            record.setOilAddType(param.getOilAddType());
            appMachOilRecordMapper.updateByPrimaryKeySelective(record);

            //统计每日用油量
            this.statOilAdd(machId, time);
        }
    }

    @Override
    public void delOilRecord(MachOilAddDel param) throws BizException {
        AppMachOilRecord record = appMachOilRecordMapper.selectOilAddByMachIdAndTime(param.getMachId(), param.getTime());
        if (record != null && (record.getOilAddHardware() == null || record.getOilAddHardware() <= 0)) {
            appMachOilRecordMapper.deleteByPrimaryKey(record.getId());
        }
    }

    @Override
    public List<AppMachDTO> getMachListByIds(List<Integer> machIds) {
        List<AppMachDTO> list = appMachMapper.selectByMachIds(machIds);
        return list;
    }

    @Override
    public AppMach getMachById(Integer machId) {
        AppMach appMachDTO = appMachMapper.selectByPrimaryKey(machId);
        return appMachDTO;
    }

    @Override
    public List<AppMachDTO> getMachListByDeptId(Integer deptId) {
        List<AppMachDTO> list = appMachMapper.selectByDeptId(deptId);
        return list;
    }

    @Override
    public List<Integer> getMachIds(List<String> snList) {
        return appMachMapper.selectMachIdByDeviceSn(snList);
    }

    @Override
    public boolean validDeptMachId(Integer deptId, Integer machId) throws BizException {
        if (deptId == null || machId == null) {
            return false;
        }
        //查找组织机构ID及其子孙组织机构ID
        List<Integer> deptIdList = sysDeptService.getDescendantDeptIdList(deptId);
        //查找组织机构下是否有该设备
        machId = appMachMapper.selectByDeptIdsAndMachId(deptIdList, machId);
        return machId != null;
    }

    @Override
    public void sendMachCmd(MachCmdParam cmdParam) throws BizException {
        Integer machId = cmdParam.getMachId();
        Integer subCmd = cmdParam.getSubCmd();
        AppMachDevice machDevice = appMachDeviceMapper.selectByMachId(machId);
        if (machDevice == null) {
            throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "未绑定硬件");
        }
        Integer deviceId = machDevice.getDeviceId();

        JSONObject param = new JSONObject();
        param.put("subCmd", subCmd);
        if (!ObjectUtils.isEmpty(cmdParam.getSpeed())) {
            param.put("speed", cmdParam.getSpeed());
        }

        AppDeviceCmdDTO cmdDTO = new AppDeviceCmdDTO();
        cmdDTO.setDeviceId(deviceId);
        cmdDTO.setObjectId(machId);
        cmdDTO.setCmd(CMD);
        cmdDTO.setParam(param.toString());

        commonDeviceService.pubDeviceCmd(cmdDTO);

        amqpTemplate.convertAndSend(QueueConst.MACH_MSG_0X8B, JSONUtil.toString(cmdDTO));
    }

    @Override
    public List<AppMachDay> selectByPrimaryKey(List<String> ids) throws BizException {
        return appMachDayMapper.selectByPrimaryKeys(ids);
    }

    @Override
    public List<AppMach> selectByMach(List<String> ids) throws BizException {
        return appMachDayMapper.selectByMach(ids);
    }

    @Override
    public List<AppMach> selectByPrimaryKey(Integer deptId) {
        return appMachDayMapper.selectByPrimaryKeyHold(deptId);
    }

    @Override
    public List<AppMach> selectEquipmentList(EquipmentIdReq req) {
        return appMachDayMapper.selectEquipmentList(req);
    }


    /**
     * 填充OBD数据到excel
     *
     * @param sheet
     * @param appMachDTO
     * @param rowIdx
     */
    private void fillObdData(HSSFSheet sheet, AppMachDTO appMachDTO, int rowIdx) {
        MachInfoExcelDTO machInfoExcelDTO = this.changeData(appMachDTO);

        HSSFRow row = sheet.createRow(rowIdx);
        HSSFCell cell0 = row.createCell(0);
        cell0.setCellValue(machInfoExcelDTO.getMachCode());

        HSSFCell cell1 = row.createCell(1);
        cell1.setCellValue(machInfoExcelDTO.getMachTypeName());

        HSSFCell cell2 = row.createCell(2);
        cell2.setCellValue(machInfoExcelDTO.getMachModelName());

        HSSFCell cell3 = row.createCell(3);
        cell3.setCellValue(machInfoExcelDTO.getDeptName());

        HSSFCell cell4 = row.createCell(4);
        cell4.setCellValue(machInfoExcelDTO.getDeliveryTimeStr());

        HSSFCell cell5 = row.createCell(5);
        cell5.setCellValue(machInfoExcelDTO.getOuterTimeStr());

        HSSFCell cell6 = row.createCell(6);
        cell6.setCellValue(machInfoExcelDTO.getTotalWorkHours());

        HSSFCell cell7 = row.createCell(7);
        cell7.setCellValue(machInfoExcelDTO.getTotalOilWear());

        HSSFCell cell8 = row.createCell(8);
        cell8.setCellValue(machInfoExcelDTO.getMile());

        HSSFCell cell9 = row.createCell(9);
        cell9.setCellValue(machInfoExcelDTO.getNames());

        HSSFCell cell10 = row.createCell(10);
        cell10.setCellValue(machInfoExcelDTO.getPhones());

        HSSFCell cell11 = row.createCell(11);
        cell11.setCellValue(machInfoExcelDTO.getCerts());

        HSSFCell cell12 = row.createCell(12);
        cell12.setCellValue(machInfoExcelDTO.getSn());

        HSSFCell cell13 = row.createCell(13);
        cell13.setCellValue(machInfoExcelDTO.getMaintainTime());

        HSSFCell cell14 = row.createCell(14);
        cell14.setCellValue(machInfoExcelDTO.getMaintainState());

        HSSFCell cell15 = row.createCell(15);
        cell15.setCellValue(machInfoExcelDTO.getLocation());
    }

    /**
     * 转换成导出excel数据
     *
     * @param appMachDTO
     * @return
     */
    private MachInfoExcelDTO changeData(AppMachDTO appMachDTO) {
        Integer machId = appMachDTO.getMachId();

        // 查找操作手
        String names = "";
        String certs = "";
        String phones = "";
        List<MachOperEmpDTO> operators = appMachOperEmpMapper.selectByMachId(machId);
        if (operators != null && operators.size() > 0) {
            List<String> nameList = new ArrayList<>();
            List<String> phoneList = new ArrayList<>();
            List<String> certList = new ArrayList<>();

            for (MachOperEmpDTO machOperEmpDTO : operators) {
                nameList.add(machOperEmpDTO.getOperEmpName());
                phoneList.add(machOperEmpDTO.getPhone());
                certList.add(machOperEmpDTO.getOperEmpCert());
            }
            names = String.join(",", nameList);
            phones = String.join(",", phoneList);
            certs = String.join(",", certList);
        }

        Date deliveryTime = appMachDTO.getDeliveryTime();
        Date enterTime = appMachDTO.getEnterTime();
        Date outerTime = appMachDTO.getOuterTime();
        Date maintainTime = appMachDTO.getMaintainTime();
        String deliveryTimeStr = "";
        String enterTimeStr = "";
        String outerTimeStr = "";
        String maintainTimeStr = "";
        if (deliveryTime != null) {
            deliveryTimeStr = DateUtil.formatDate(deliveryTime);
        }
        if (enterTime != null) {
            enterTimeStr = DateUtil.formatDate(enterTime);
        }
        if (outerTime != null) {
            outerTimeStr = DateUtil.formatDate(outerTime);
        }
        if (maintainTime != null) {
            maintainTimeStr = DateUtil.formatDate(maintainTime, "yyyy-MM-dd HH:mm:ss");
        }

        MachInfoExcelDTO data = new MachInfoExcelDTO();
        BeanUtils.copyProperties(appMachDTO, data);
        data.setCerts(certs);
        data.setNames(names);
        data.setPhones(phones);
        data.setDeliveryTimeStr(deliveryTimeStr);
        data.setEnterTimeStr(enterTimeStr);
        data.setOuterTimeStr(outerTimeStr);
        data.setMaintainTime(maintainTimeStr);
        Integer maintainState = appMachDTO.getMaintainState();
        String maintainStateStr = "-";
        if (maintainState != null) {
            maintainStateStr = maintainState == 0 ? "是" : "否";
        }
        data.setMaintainState(maintainStateStr);
        return data;
    }

    /**
     * 统计加油量
     *
     * @param machId
     * @param time
     */
    private void statOilAdd(Integer machId, Date time) {
        Date startTime = DateUtil.getDateBegin(time);
        Date endTime = DateUtil.getDateEnd(time);
        AppMach appMach = appMachMapper.selectByPrimaryKey(machId);
        AppMachOilRecordDTO stat = appMachOilRecordMapper.selectOilAddStatByMachIdAndTimeRange(machId, startTime, endTime);
        AppMachDay machDay = new AppMachDay();
        machDay.setHoldDeptId(appMach.getHoldDeptId());
        machDay.setMachId(machId);
        machDay.setDate(time);
        machDay.setOilAdd(stat.getOilAdd());
        appMachDayMapper.insertUpdate(machDay);
    }
}
